/*
 * 13.9
 * Write a smart pointer (smart_ptr) class.
 */
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;

template <typename T>
class smart_ptr
{
public:
    smart_ptr(T *ptr = 0) {
        this->ptr = ptr;
        ref_count = new int(1);
    }
    ~smart_ptr() {
        if (--*ref_count == 0) {
            delete ptr; /* assume delete */
            delete ref_count;
        }
    }
    smart_ptr(const smart_ptr &other) {
        ptr = other.ptr;
        ref_count = other.ref_count;
        ++*ref_count;
    }
    smart_ptr &operator=(const smart_ptr &other) {
        smart_ptr(other).swap(*this);
        return *this;
    }
    T &operator*() const { /* XXX: note reference and const */
        return *ptr;
    }
    T *operator->() const { /* XXX: note const */
        return ptr;
    }
    void swap(smart_ptr &other) {
        std::swap(ptr, other.ptr);
        std::swap(ref_count, other.ref_count);
    }
private:
    T *ptr;
    int *ref_count;
};

class myint
{
public:
    myint(int i) {
        this->i = i;
    }
    void seti(int i) {
        this->i = i;
    }
    void print() const {
        cout << i << endl;
    }
private:
    int i;
};

int main()
{
    smart_ptr<int> pi;
    pi = smart_ptr<int>(new int(1));
    vector<smart_ptr<myint> > vec;
    vec.push_back(smart_ptr<myint>(new myint(1)));
    vec.push_back(smart_ptr<myint>(new myint(2)));
    vec.push_back(smart_ptr<myint>(new myint(3)));
    for (vector<smart_ptr<myint> >::const_iterator it = vec.begin(); it != vec.end(); ++it) {
        (*it)->print();
    }
    for (vector<smart_ptr<myint> >::iterator it = vec.begin(); it != vec.end(); ++it) {
        (**it).seti(5); 
        (**it).print();
        smart_ptr<myint> &t = *it;
        t->seti(10); 
        (*t).print();
    }
    return 0;
}
